package com.dynamic.mybatis.core.parser.field;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.dynamic.mybatis.core.enums.CommandType;
import com.dynamic.mybatis.core.enums.ReturnType;
import com.dynamic.mybatis.core.enums.Type;
import com.dynamic.mybatis.core.enums.TypeAlias;
import com.dynamic.mybatis.core.metadata.DynamicMappedStatement;
import com.dynamic.mybatis.core.metadata.DynamicPage;
import com.dynamic.mybatis.core.metadata.MappedStatementMetaField;
import com.dynamic.mybatis.core.session.DynamicSqlSession;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandlerRegistry;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @Description
 * @Author xs
 * @Date 2022/11/17 11:05
 */
public abstract class DynamicMappedStatementOutputParameterFieldParser  extends DynamicMappedStatementDataBaseFieldParser{

    private TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();

    public DynamicMappedStatementOutputParameterFieldParser(DynamicSqlSession dynamicSqlSession) {
        super(dynamicSqlSession);
    }

    public MappedStatementMetaField outputParameterFieldParser(DynamicMappedStatement dms) {
        MappedStatementMetaField field = new MappedStatementMetaField();

        Type type = Type.getType(dms.getReturnType().getType());
        if(type != null){
            field.setType(type.getType());
        }else if(dms.getCommandType() != CommandType.StandardCommand.SELECT){} {
            field.setType(Type.StandardType.INTEGER.type);
        }
        return outputParameterFieldWrapper(field,dms);
    }



    /**
     　* @Description: 获取动态SQL结果集信息
     　* @param configuration mybatis configuration
     　* @param connection 数据库链接
       * @param dms 原生SQL或者mybatis动态SQL
    */
    public MappedStatementMetaField outputParameterFieldParser(List<MappedStatementMetaField> databaseFields,DynamicMappedStatement dms){
        if(CollectionUtils.isNotEmpty(databaseFields)){
          databaseFields.stream().forEach(f ->  { if(f.getValidator() != null){f.getValidator().setEnable(Boolean.FALSE);}});
        }
        MappedStatement mappedStatement = getConfiguration().getMappedStatement(dms.getId());
        MappedStatementMetaField msf = new MappedStatementMetaField();
        if(mappedStatement == null || CollectionUtils.isEmpty(mappedStatement.getResultMaps())){
            return msf;
        }
        ResultMap resultMap = mappedStatement.getResultMaps().get(0);

        msf =   getJavaResultMapping(mappedStatement,resultMap);
        //基础类型mybatis有对应的TypeHandler
        //@see org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject  hasTypeHandlerForResultObject

        boolean hasTypeHandler =  typeHandlerRegistry.hasTypeHandler(resultMap.getType(),JdbcType.forCode(databaseFields.get(0).getJdbcType().getVendorTypeNumber()));

        if(dms.getReturnType() == ReturnType.StandardReturnType.COLLECT){//数组
            msf.setType(Type.StandardType.ARRAY.name().toLowerCase());
            msf.setGenericType(TypeAlias.getTypeAlias(resultMap.getType()));
          //  msf.setName(mappedStatement.getId());
        }else if(dms.getReturnType() == ReturnType.StandardReturnType.PAGE){//分页
            msf.setType(Type.StandardType.STRUCT.name().toLowerCase());

            List<MappedStatementMetaField> children = new ArrayList<>();
            MappedStatementMetaField pageNumberField = new MappedStatementMetaField();
            pageNumberField.setType(Type.StandardType.BIGINT.type);
            pageNumberField.setName("当前页");
            pageNumberField.setField(DynamicPage.PAGE_NUMBER);
            children.add(pageNumberField);

            MappedStatementMetaField pageSizeField = new MappedStatementMetaField();
            pageSizeField.setType(Type.StandardType.BIGINT.type);
            pageSizeField.setName("每页数量");
            pageSizeField.setField(DynamicPage.PAGE_SIZE);
            children.add(pageSizeField);

            MappedStatementMetaField totalField = new MappedStatementMetaField();
            totalField.setType(Type.StandardType.BIGINT.type);
            totalField.setName("总数量");
            totalField.setField(DynamicPage.TOTAL);
            children.add(totalField);


            MappedStatementMetaField recordsField = new MappedStatementMetaField();
            recordsField.setType(Type.StandardType.ARRAY.type);
            if(hasTypeHandler){
                recordsField.setType(TypeAlias.getTypeAlias(resultMap.getType()));
                recordsField.setJdbcType(databaseFields.get(0).getJdbcType());
                recordsField.setGenericType(TypeAlias.getTypeAlias(resultMap.getType()));
            }else {
                recordsField.setGenericType(TypeAlias.getTypeAlias(resultMap.getType()));
            }
            recordsField.setName("结果集");
            recordsField.setField(DynamicPage.RECORDS);
            if(!hasTypeHandler && CollectionUtils.isEmpty(msf.getChildren())){
                recordsField.setChildren(mergeDataBseToJavaBatch(databaseFields,msf.getChildren(),Boolean.FALSE));
            }
            children.add(recordsField);

            msf.setChildren(children);

        }else if(dms.getReturnType() == ReturnType.StandardReturnType.MAP){
            msf.setType(Type.StandardType.STRUCT.type);
        }else if(hasTypeHandler){//基本数据类型
            msf.setType(TypeAlias.getTypeAlias(resultMap.getType()));
            msf.setJdbcType(databaseFields.get(0).getJdbcType());
        }else {
            msf.setGenericType(TypeAlias.getTypeAlias(resultMap.getType()));
        }
        if(!hasTypeHandler && CollectionUtils.isEmpty(msf.getChildren())){
            msf.setChildren(mergeDataBseToJavaBatch(databaseFields,msf.getChildren(),Boolean.FALSE));
        }
        return  outputParameterFieldWrapper(msf,dms);
    }


    public MappedStatementMetaField outputParameterFieldWrapper(MappedStatementMetaField field,DynamicMappedStatement dms){
        if(StringUtils.isBlank(dms.getResultWrapper())){
            return field;
        }
        MappedStatementMetaField next =  new MappedStatementMetaField();
        next.setType(Type.StandardType.STRUCT.type);
        MappedStatementMetaField first = next;
        MappedStatementMetaField pre = null;
        String lastKey = null;
        String[] keys = dms.getResultWrapper().split("\\.");
        for(int i = 0 ; i < keys.length ; i ++){
            String key = lastKey = keys[i];
            MappedStatementMetaField  temp = new MappedStatementMetaField();
            temp.setType(Type.StandardType.STRUCT.type);
            temp.setField(key);
            temp.setChildren(new ArrayList<>());
            next.setChildren(new ArrayList<>());
            next.getChildren().add(temp);
            pre = next;
            next = temp;
        }
        if(Objects.equals(field.getType(), Type.StandardType.STRUCT.type)){
            next.getChildren().addAll(field.getChildren());
        }else {
            pre.getChildren().clear();
            field.setField(lastKey);
            pre.getChildren().add(field);
        }
        return first;
    }



        /**
         　* @Description: mybatis 一对多关系 一对一层级关系
         　*/
    private List<MappedStatementMetaField>  getJavaResultMapping(MappedStatement mappedStatement){
        if(CollectionUtils.isEmpty(mappedStatement.getResultMaps())){
            return null;
        }
        return getJavaResultMapping(mappedStatement,mappedStatement.getResultMaps().get(0)).getChildren();
    }

    private MappedStatementMetaField  getJavaResultMapping(MappedStatement mappedStatement,ResultMap resultMap){
        MappedStatementMetaField fieldVo = new MappedStatementMetaField();
        if(resultMap == null){return fieldVo;}
        fieldVo.setJavaTypeClass(resultMap.getType());
        List<ResultMapping> resultMappings =  resultMap.getResultMappings();
        if(CollectionUtils.isEmpty(resultMappings)){return fieldVo;}

        List<MappedStatementMetaField> fieldMappings = new ArrayList<>();
        int sort = 1;
        for(ResultMapping mapping : resultMappings){
            MappedStatementMetaField childFieldVo = new MappedStatementMetaField();
            String field = com.dynamic.mybatis.core.toolkit.StringUtils.getNotEmpty(mapping.getProperty(),mapping.getColumn());
            childFieldVo.setField(field);
            childFieldVo.setName(field);
            childFieldVo.setSort((byte)sort++);
            String nestedResultMapId = mapping.getNestedResultMapId();
            ResultMap childrenMap;
            if(StringUtils.isNotBlank(nestedResultMapId) &&
                    (childrenMap = mappedStatement.getConfiguration().getResultMap(mapping.getNestedResultMapId())) != null){
                childFieldVo.setJavaTypeClass(childrenMap.getType());
                MappedStatementMetaField  children = getJavaResultMapping(mappedStatement,childrenMap);
                childFieldVo.setChildren(children.getChildren());
            }
            fieldMappings.add(childFieldVo);
        }
        fieldVo.setChildren(fieldMappings);
        return fieldVo;
    }

}